Data visualization - Final Project


Source: National Health and Nutrition Examination Survey

The National Health and Nutrition Examination Survey is a program designed to asses the health and nutritional status of adults and children in the United States. NHANES is a major program of the National Center for Health Statistics (NCHS). NCHS is part of the Centers for Disease Control and Prevention (CDC).

NHANES 2015–2016 data source was selected since it includes LDL and Triglycerides needed for analysis

Data source documentation, codebook and frequencies

Demographic data from surveys:

Cholesterol - Low Density Lipoprotein (LDL) and Triglycerides lab results:

Cholesterol - High Density Lipoprotein (HDL) lab results:


Loading R libraries

library(tidyverse) #loads ggplot, dplyr, readr
library(SASxport) #loads data in xport format - SAS
library(plotly) #builds interactive graphs
library(gifski)
library(gganimate)
library(leaflet)

Loading cholesterol - LDL and Triglycerides lab results

trigly <- read.xport("../data/TRIGLY_I.XPT")

Loading cholesterol - HDL lab results

hdl <- read.xport("../data/HDL_I.XPT")

Loading demographic data

demo <- read.xport("../data/DEMO_I.XPT")

Loading map data from usa map

usa <- map_data("usa")

Exploratory data analysis

Coding heart disease risk based on LDL score

trigly <- trigly %>%
  mutate(
    RISK = case_when(
      LBDLDL <= 130 ~ "low",
      LBDLDL >= 190 ~ "high",
      TRUE ~ "medium"
    )
  )
# table with risk values
table(trigly$RISK)

  high    low medium 
    57   2056   1078 

Getting race and gender demographics about patients with LDL data

# joining trigly data with demographic by respondent sequence number
demo_trigly <- trigly %>%
  inner_join(demo) %>%
  mutate(
    RIDRETH1 = case_when(
      RIDRETH1 == 1 ~ "Mexican American",
      RIDRETH1 == 2 ~ "Other Hispanic",
      RIDRETH1 == 3 ~ "Non-Hispanic White",
      RIDRETH1 == 4 ~ "Non-Hispanic Black",
      RIDRETH1 == 5 ~ "Other Race"
    ),
    RIAGENDR = case_when(
      RIAGENDR == 1 ~ "Male",
      RIAGENDR == 2 ~ "Female"
    )
  )
Joining, by = "SEQN"
# table with risk values and gender
table(demo_trigly$RIAGENDR, demo_trigly$RISK)
        
         high  low medium
  Female   26 1062    538
  Male     31  994    540
# table with risk values and race/ethnicity
table(demo_trigly$RIDRETH1, demo_trigly$RISK)
                    
                     high low medium
  Mexican American      6 370    162
  Non-Hispanic Black   13 451    245
  Non-Hispanic White   23 657    358
  Other Hispanic        7 280    133
  Other Race            8 298    180

Visualizing heart disease risk by gender

# filtering risk
demo_trigly_risk_gender <- demo_trigly %>%
  filter(RISK == 'high') %>% # setting fixed value, shiny app will use input select
  group_by(RIAGENDR) %>%
  summarize(count = n())
colors = c("#B80095", "#3008B1")
p <- plot_ly(demo_trigly_risk_gender, labels = ~RIAGENDR, values = ~count, type = 'pie',
             marker = list(colors = colors))
p <- p %>% layout(title = 'Heart disease risk by gender',
         xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
         yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
p

Visualizing heart disease risk by gender and race

# filtering risk
demo_trigly_gender_race <- demo_trigly %>%
  filter(RISK == 'high') # setting fixed value, shiny app will use input select
p <- ggplot(data = demo_trigly_gender_race, mapping = aes(x = RIDRETH1, fill = RIAGENDR)) +
  geom_bar(position = "dodge", mapping = aes(y = ..prop.., group = RIAGENDR)) +
  scale_fill_manual(values = c("#B80095", "#3008B1")) +
  theme(panel.border = element_blank(), 
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_text(angle = 25, hjust = 1)
        ) +
  labs(title = "Heart disease risk by gender and race",
       subtitle = "Risk based on LDL level",
       x = "Race and Ethnicity",
       y = "Risk percentage %",
       fill = "Gender") 
  # transition_states(RIAGENDR) +
  #     ease_aes('linear')
  #   anim_save("../shiny/www/gganimate02.gif", animate(p))
ggplotly(p)

Coding Marital status

demo_trigly <- demo_trigly %>%
  mutate(
    DMDMARTL = case_when(
      DMDMARTL == 1 ~ "Married",
      DMDMARTL == 2 ~ "Widowed",
      DMDMARTL == 3 ~ "Divorced",
      DMDMARTL == 4 ~ "Separated",
      DMDMARTL == 5 ~ "Never married",
      DMDMARTL == 6 ~ "Living with partner"
    )
  )
# table marital status and heart disease risk
table(demo_trigly$DMDMARTL,demo_trigly$RISK)
                     
                      high low medium
  Divorced               7 163    111
  Living with partner    9 150     67
  Married               26 806    497
  Never married          6 315    147
  Separated              2  45     40
  Widowed                4 132     70

Visualizing heart disease risk by marital status

# filtering risk
demo_trigly_marital <- demo_trigly %>%
  group_by(DMDMARTL,RISK) %>%
  summarize(count = n()) %>%
  drop_na()
p <- ggplot(data = demo_trigly_marital, mapping = aes(x = reorder(DMDMARTL,-count), y = count)) +
  geom_col(mapping = aes(fill = RISK)) +
  coord_flip() +
  scale_fill_manual(values = c("#FF3500", "#FF7D05", "#FFC300")) +
  theme(panel.border = element_blank(), 
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_text(angle = 0, hjust = 1)
        ) +
  labs(title = "Heart disease risk by marital status",
       subtitle = "Risk based on LDL level",
       x = "Marital status",
       y = "Total patients",
       fill = "Risk level")
  # transition_reveal(count) +
  #     ease_aes('linear')
  #   anim_save("../shiny/www/gganimate01.gif", animate(p))
ggplotly(p)

Education level and heart disease risk

# table marital status and heart disease risk
table(demo_trigly$DMDHREDU,demo_trigly$RISK)
   
    high low medium
  1    6 236    112
  2    7 219    133
  3   12 428    236
  4   16 611    306
  5   13 474    254
  9    1   6      2

Visualizing Heart disease risk by education level

demo_trigly_education <- demo_trigly %>%
  filter(DMDHREDU <= 5)
p <- ggplot(data = demo_trigly_education, mapping = aes(x = DMDHREDU, y = LBDLDL)) +
  geom_point(color = "#FFC300", alpha = 0.4) +
  geom_smooth(size = 1.1, method = "loess", se = FALSE) +
  scale_x_log10() +
  theme(strip.background = element_rect(
     fill="#FF7D05", size=1.5, linetype="solid"
     ),panel.border = element_blank(), 
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_text(angle = 0, hjust = 1)
     )+
  facet_wrap(~RISK, ncol = 3) +
  labs(x = "Education Level (1 - lowest, 5 - highest)",
       y = "LDL Levels",
       title = "Heart disease risk by education level",
       subtitle = "Risk based on LDL level")
ggplotly(p)
Don't know how to automatically pick scale for object of type labelled/integer. Defaulting to continuous.
Removed 478 rows containing non-finite values (stat_smooth).pseudoinverse used at 0.70246neighborhood radius 0.22534reciprocal condition number  6.0207e-17There are other near singularities as well. 0.090619pseudoinverse used at 0.70246neighborhood radius 0.22534reciprocal condition number  7.8557e-17There are other near singularities as well. 0.090619pseudoinverse used at 0.70246neighborhood radius 0.22534reciprocal condition number  4.2613e-17There are other near singularities as well. 0.090619

Annual household income of patients in study

table(demo_trigly$INDHHIN2)

  1   2   3   4   5   6   7   8   9  10  12  13  14  15  77  99 
 76 114 188 192 186 390 310 246 187 157  79  58 298 485  82  45 

Visualizing Heart disease risk by Annual household income

p <- ggplot(data = demo_trigly, mapping = aes(x = INDHHIN2, fill = RISK)) +
  geom_density(alpha = 0.7) +
  scale_x_log10() +
  scale_fill_manual(values = c("#FF3500", "#FFC300", "#FF7D05")) +
  labs(x = "Annual Household Income (1 - lowest, 100 - highest)",
       y = "Risk score",
       title = "Heart disease risk by annual household income",
       subtitle = "Risk based on LDL level")
ggplotly(p)
Removed 98 rows containing non-finite values (stat_density).

Visualizing National Center for Health Statistics region

# filtering Maryland region, where National Center for Health Statistics is located at
states <- map_data("state")
nchs_region <- states %>%
  filter(region == 'maryland')
p <- ggplot() +
  geom_polygon(data = states, aes(x=long,y=lat, group = group, fill=region),color="white", alpha = 0.3) +
  geom_polygon(data = nchs_region, aes(x=long,y=lat, group = group, fill=region),color="white") +
  labs(title = "National Center for Health Statistics - Maryland") +
  theme_void()
  guides(fill = FALSE)
$fill
[1] FALSE

attr(,"class")
[1] "guides"
ggplotly(p) %>% layout(showlegend = FALSE)

Visualizing National Center for Health Statistics region

# National Center for Health Statistics coordenates 
m <- leaflet() %>%
  addTiles() %>%
  addMarkers(lng=-76.951720,
             lat=38.969450,
             label="National Center for Health Statistics",
             labelOptions = labelOptions(noHide=T))
m
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgQ2hvbGVzdGVyb2wgTGV2ZWxzIGluIHRoZSBVbml0ZWQgU3RhdGVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiAiSnVhbiBDYXJiYWxsbyIKY2xhc3M6ICJEYXRhIFZpc3VhbGl6YXRpb24gLSBGaW5hbCBQcm9qZWN0IgotLS0KIyMgRGF0YSB2aXN1YWxpemF0aW9uIC0gRmluYWwgUHJvamVjdAoqKioKIyMjIFNvdXJjZTogTmF0aW9uYWwgSGVhbHRoIGFuZCBOdXRyaXRpb24gRXhhbWluYXRpb24gU3VydmV5IAojIyMjIGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9pbmRleC5odG0KIyMjIyBUaGUgTmF0aW9uYWwgSGVhbHRoIGFuZCBOdXRyaXRpb24gRXhhbWluYXRpb24gU3VydmV5IGlzIGEgcHJvZ3JhbSBkZXNpZ25lZCB0byBhc3NlcyB0aGUgaGVhbHRoIGFuZCBudXRyaXRpb25hbCBzdGF0dXMgb2YgYWR1bHRzIGFuZCBjaGlsZHJlbiBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gTkhBTkVTIGlzIGEgbWFqb3IgcHJvZ3JhbSBvZiB0aGUgTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljcyAoTkNIUykuIE5DSFMgaXMgcGFydCBvZiB0aGUgQ2VudGVycyBmb3IgRGlzZWFzZSBDb250cm9sIGFuZCBQcmV2ZW50aW9uIChDREMpLgoKIyMjIyBUaGUgc3VydmV5IGV4YW1pbmVzIGEgc2FtcGxlIG9mIDUsMDAwIHBlcnNvbnMgZWFjaCB5ZWFyLCBsb2NhdGVkIGluIGNvdW50aWVzIGFjcm9zcyB0aGUgY291bnRyeS4gTkhBTkVTIGludGVydmlldyBpbmNsdWRlcyBkZW1vZ3JhcGhpYywgc29jaW9lY29ub21pYywgZGlldGFyeSwgYW5kIGhlYWx0aC1yZWxhdGVkIHF1ZXN0aW9ucy4gRXhhbWluYXRpb24gY29tcG9uZW50IGNvbnNpc3RzIG9mIG1lZGljYWwsIGRlbnRhbCwgcGh5c2lvbG9naWNhbCBtZWFzdXJlbWVudHMgYW5kIGxhYm9yYXRvcnkgdGVzdHMuCioqKgojIyMjIE5IQU5FUyAyMDE14oCTMjAxNiBkYXRhIHNvdXJjZSB3YXMgc2VsZWN0ZWQgc2luY2UgaXQgaW5jbHVkZXMgTERMIGFuZCBUcmlnbHljZXJpZGVzIG5lZWRlZCBmb3IgYW5hbHlzaXMKIyMjIERhdGEgc291cmNlIHdhcyBkb3dubG9hZGVkIGZyb20gdGhlIGZvbGxvd2luZyBsaW5rOiAKIyMjIyBodHRwczovL3d3d24uY2RjLmdvdi9uY2hzL25oYW5lcy9zZWFyY2gvZGF0YXBhZ2UuYXNweD9Db21wb25lbnQ9TGFib3JhdG9yeSZDeWNsZUJlZ2luWWVhcj0yMDE1CiMjIyBEYXRhIHNvdXJjZSBkb2N1bWVudGF0aW9uLCBjb2RlYm9vayBhbmQgZnJlcXVlbmNpZXMKIyMjIyBEZW1vZ3JhcGhpYyBkYXRhIGZyb20gc3VydmV5czoKIyMjIyBodHRwczovL3d3d24uY2RjLmdvdi9OY2hzL05oYW5lcy8yMDE1LTIwMTYvREVNT19JLmh0bQojIyMjCiMjIyMgQ2hvbGVzdGVyb2wgLSBMb3cgRGVuc2l0eSBMaXBvcHJvdGVpbiAoTERMKSBhbmQgVHJpZ2x5Y2VyaWRlcyBsYWIgcmVzdWx0czogCiMjIyMgaHR0cHM6Ly93d3duLmNkYy5nb3YvTmNocy9OaGFuZXMvMjAxNS0yMDE2L1RSSUdMWV9JLmh0bQojIyMjCiMjIyMgQ2hvbGVzdGVyb2wgLSBIaWdoIERlbnNpdHkgTGlwb3Byb3RlaW4gKEhETCkgbGFiIHJlc3VsdHM6IAojIyMjIGh0dHBzOi8vd3d3bi5jZGMuZ292L05jaHMvTmhhbmVzLzIwMTUtMjAxNi9IRExfSS5odG0KIyMjIwoqKioKCiMjIyBMb2FkaW5nIFIgbGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkgI2xvYWRzIGdncGxvdCwgZHBseXIsIHJlYWRyCmxpYnJhcnkoU0FTeHBvcnQpICNsb2FkcyBkYXRhIGluIHhwb3J0IGZvcm1hdCAtIFNBUwpsaWJyYXJ5KHBsb3RseSkgI2J1aWxkcyBpbnRlcmFjdGl2ZSBncmFwaHMKbGlicmFyeShnaWZza2kpCmxpYnJhcnkoZ2dhbmltYXRlKQpsaWJyYXJ5KGxlYWZsZXQpCmBgYAoKIyMjIExvYWRpbmcgY2hvbGVzdGVyb2wgLSBMREwgYW5kIFRyaWdseWNlcmlkZXMgbGFiIHJlc3VsdHMKYGBge3J9CnRyaWdseSA8LSByZWFkLnhwb3J0KCIuLi9kYXRhL1RSSUdMWV9JLlhQVCIpCmBgYAoKIyMjIExvYWRpbmcgY2hvbGVzdGVyb2wgLSBIREwgbGFiIHJlc3VsdHMKYGBge3J9CmhkbCA8LSByZWFkLnhwb3J0KCIuLi9kYXRhL0hETF9JLlhQVCIpCmBgYAoKIyMjIExvYWRpbmcgZGVtb2dyYXBoaWMgZGF0YQpgYGB7cn0KZGVtbyA8LSByZWFkLnhwb3J0KCIuLi9kYXRhL0RFTU9fSS5YUFQiKQpgYGAKCiMjIyBMb2FkaW5nIG1hcCBkYXRhIGZyb20gdXNhIG1hcApgYGB7cn0KdXNhIDwtIG1hcF9kYXRhKCJ1c2EiKQpgYGAKCiMjIyBFeHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzCiMjIyMgQ29kaW5nIGhlYXJ0IGRpc2Vhc2UgcmlzayBiYXNlZCBvbiBMREwgc2NvcmUKYGBge3J9CnRyaWdseSA8LSB0cmlnbHkgJT4lCiAgbXV0YXRlKAogICAgUklTSyA9IGNhc2Vfd2hlbigKICAgICAgTEJETERMIDw9IDEzMCB+ICJsb3ciLAogICAgICBMQkRMREwgPj0gMTkwIH4gImhpZ2giLAogICAgICBUUlVFIH4gIm1lZGl1bSIKICAgICkKICApCiMgdGFibGUgd2l0aCByaXNrIHZhbHVlcwp0YWJsZSh0cmlnbHkkUklTSykKYGBgCgojIyMjIEdldHRpbmcgcmFjZSBhbmQgZ2VuZGVyIGRlbW9ncmFwaGljcyBhYm91dCBwYXRpZW50cyB3aXRoIExETCBkYXRhCmBgYHtyfQojIGpvaW5pbmcgdHJpZ2x5IGRhdGEgd2l0aCBkZW1vZ3JhcGhpYyBieSByZXNwb25kZW50IHNlcXVlbmNlIG51bWJlcgpkZW1vX3RyaWdseSA8LSB0cmlnbHkgJT4lCiAgaW5uZXJfam9pbihkZW1vKSAlPiUKICBtdXRhdGUoCiAgICBSSURSRVRIMSA9IGNhc2Vfd2hlbigKICAgICAgUklEUkVUSDEgPT0gMSB+ICJNZXhpY2FuIEFtZXJpY2FuIiwKICAgICAgUklEUkVUSDEgPT0gMiB+ICJPdGhlciBIaXNwYW5pYyIsCiAgICAgIFJJRFJFVEgxID09IDMgfiAiTm9uLUhpc3BhbmljIFdoaXRlIiwKICAgICAgUklEUkVUSDEgPT0gNCB+ICJOb24tSGlzcGFuaWMgQmxhY2siLAogICAgICBSSURSRVRIMSA9PSA1IH4gIk90aGVyIFJhY2UiCiAgICApLAogICAgUklBR0VORFIgPSBjYXNlX3doZW4oCiAgICAgIFJJQUdFTkRSID09IDEgfiAiTWFsZSIsCiAgICAgIFJJQUdFTkRSID09IDIgfiAiRmVtYWxlIgogICAgKQogICkKCiMgdGFibGUgd2l0aCByaXNrIHZhbHVlcyBhbmQgZ2VuZGVyCnRhYmxlKGRlbW9fdHJpZ2x5JFJJQUdFTkRSLCBkZW1vX3RyaWdseSRSSVNLKQoKIyB0YWJsZSB3aXRoIHJpc2sgdmFsdWVzIGFuZCByYWNlL2V0aG5pY2l0eQp0YWJsZShkZW1vX3RyaWdseSRSSURSRVRIMSwgZGVtb190cmlnbHkkUklTSykKCmBgYAoKIyMjIyBWaXN1YWxpemluZyBoZWFydCBkaXNlYXNlIHJpc2sgYnkgZ2VuZGVyCmBgYHtyfQojIGZpbHRlcmluZyByaXNrCmRlbW9fdHJpZ2x5X3Jpc2tfZ2VuZGVyIDwtIGRlbW9fdHJpZ2x5ICU+JQogIGZpbHRlcihSSVNLID09ICdoaWdoJykgJT4lICMgc2V0dGluZyBmaXhlZCB2YWx1ZSwgc2hpbnkgYXBwIHdpbGwgdXNlIGlucHV0IHNlbGVjdAogIGdyb3VwX2J5KFJJQUdFTkRSKSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpCgpjb2xvcnMgPSBjKCIjQjgwMDk1IiwgIiMzMDA4QjEiKQoKcCA8LSBwbG90X2x5KGRlbW9fdHJpZ2x5X3Jpc2tfZ2VuZGVyLCBsYWJlbHMgPSB+UklBR0VORFIsIHZhbHVlcyA9IH5jb3VudCwgdHlwZSA9ICdwaWUnLAogICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvcnMgPSBjb2xvcnMpKQpwIDwtIHAgJT4lIGxheW91dCh0aXRsZSA9ICdIZWFydCBkaXNlYXNlIHJpc2sgYnkgZ2VuZGVyJywKICAgICAgICAgeGF4aXMgPSBsaXN0KHNob3dncmlkID0gRkFMU0UsIHplcm9saW5lID0gRkFMU0UsIHNob3d0aWNrbGFiZWxzID0gRkFMU0UpLAogICAgICAgICB5YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGQUxTRSwgemVyb2xpbmUgPSBGQUxTRSwgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSkpCnAKYGBgCgojIyMjIFZpc3VhbGl6aW5nIGhlYXJ0IGRpc2Vhc2UgcmlzayBieSBnZW5kZXIgYW5kIHJhY2UKYGBge3J9CiMgZmlsdGVyaW5nIHJpc2sKZGVtb190cmlnbHlfZ2VuZGVyX3JhY2UgPC0gZGVtb190cmlnbHkgJT4lCiAgZmlsdGVyKFJJU0sgPT0gJ2hpZ2gnKSAjIHNldHRpbmcgZml4ZWQgdmFsdWUsIHNoaW55IGFwcCB3aWxsIHVzZSBpbnB1dCBzZWxlY3QKCnAgPC0gZ2dwbG90KGRhdGEgPSBkZW1vX3RyaWdseV9nZW5kZXJfcmFjZSwgbWFwcGluZyA9IGFlcyh4ID0gUklEUkVUSDEsIGZpbGwgPSBSSUFHRU5EUikpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIG1hcHBpbmcgPSBhZXMoeSA9IC4ucHJvcC4uLCBncm91cCA9IFJJQUdFTkRSKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNCODAwOTUiLCAiIzMwMDhCMSIpKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjUsIGhqdXN0ID0gMSkKICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIkhlYXJ0IGRpc2Vhc2UgcmlzayBieSBnZW5kZXIgYW5kIHJhY2UiLAogICAgICAgc3VidGl0bGUgPSAiUmlzayBiYXNlZCBvbiBMREwgbGV2ZWwiLAogICAgICAgeCA9ICJSYWNlIGFuZCBFdGhuaWNpdHkiLAogICAgICAgeSA9ICJSaXNrIHBlcmNlbnRhZ2UgJSIsCiAgICAgICBmaWxsID0gIkdlbmRlciIpIAogICMgdHJhbnNpdGlvbl9zdGF0ZXMoUklBR0VORFIpICsKICAjICAgICBlYXNlX2FlcygnbGluZWFyJykKICAjICAgYW5pbV9zYXZlKCIuLi9zaGlueS93d3cvZ2dhbmltYXRlMDIuZ2lmIiwgYW5pbWF0ZShwKSkKZ2dwbG90bHkocCkKYGBgCgojIyMjIENvZGluZyBNYXJpdGFsIHN0YXR1cwpgYGB7cn0KZGVtb190cmlnbHkgPC0gZGVtb190cmlnbHkgJT4lCiAgbXV0YXRlKAogICAgRE1ETUFSVEwgPSBjYXNlX3doZW4oCiAgICAgIERNRE1BUlRMID09IDEgfiAiTWFycmllZCIsCiAgICAgIERNRE1BUlRMID09IDIgfiAiV2lkb3dlZCIsCiAgICAgIERNRE1BUlRMID09IDMgfiAiRGl2b3JjZWQiLAogICAgICBETURNQVJUTCA9PSA0IH4gIlNlcGFyYXRlZCIsCiAgICAgIERNRE1BUlRMID09IDUgfiAiTmV2ZXIgbWFycmllZCIsCiAgICAgIERNRE1BUlRMID09IDYgfiAiTGl2aW5nIHdpdGggcGFydG5lciIKICAgICkKICApCgojIHRhYmxlIG1hcml0YWwgc3RhdHVzIGFuZCBoZWFydCBkaXNlYXNlIHJpc2sKdGFibGUoZGVtb190cmlnbHkkRE1ETUFSVEwsZGVtb190cmlnbHkkUklTSykKCmBgYAoKIyMjIyBWaXN1YWxpemluZyBoZWFydCBkaXNlYXNlIHJpc2sgYnkgbWFyaXRhbCBzdGF0dXMKYGBge3J9CiMgZmlsdGVyaW5nIHJpc2sKZGVtb190cmlnbHlfbWFyaXRhbCA8LSBkZW1vX3RyaWdseSAlPiUKICBncm91cF9ieShETURNQVJUTCxSSVNLKSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JQogIGRyb3BfbmEoKQoKcCA8LSBnZ3Bsb3QoZGF0YSA9IGRlbW9fdHJpZ2x5X21hcml0YWwsIG1hcHBpbmcgPSBhZXMoeCA9IHJlb3JkZXIoRE1ETUFSVEwsLWNvdW50KSwgeSA9IGNvdW50KSkgKwogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoZmlsbCA9IFJJU0spKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRkYzNTAwIiwgIiNGRjdEMDUiLCAiI0ZGQzMwMCIpKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxKQogICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiSGVhcnQgZGlzZWFzZSByaXNrIGJ5IG1hcml0YWwgc3RhdHVzIiwKICAgICAgIHN1YnRpdGxlID0gIlJpc2sgYmFzZWQgb24gTERMIGxldmVsIiwKICAgICAgIHggPSAiTWFyaXRhbCBzdGF0dXMiLAogICAgICAgeSA9ICJUb3RhbCBwYXRpZW50cyIsCiAgICAgICBmaWxsID0gIlJpc2sgbGV2ZWwiKQogICMgdHJhbnNpdGlvbl9yZXZlYWwoY291bnQpICsKICAjICAgICBlYXNlX2FlcygnbGluZWFyJykKICAjICAgYW5pbV9zYXZlKCIuLi9zaGlueS93d3cvZ2dhbmltYXRlMDEuZ2lmIiwgYW5pbWF0ZShwKSkKZ2dwbG90bHkocCkKYGBgCgojIyMjIEVkdWNhdGlvbiBsZXZlbCBhbmQgaGVhcnQgZGlzZWFzZSByaXNrCmBgYHtyfQojIHRhYmxlIG1hcml0YWwgc3RhdHVzIGFuZCBoZWFydCBkaXNlYXNlIHJpc2sKdGFibGUoZGVtb190cmlnbHkkRE1ESFJFRFUsZGVtb190cmlnbHkkUklTSykKCmBgYAoKIyMjIyBWaXN1YWxpemluZyBIZWFydCBkaXNlYXNlIHJpc2sgYnkgZWR1Y2F0aW9uIGxldmVsCmBgYHtyfQpkZW1vX3RyaWdseV9lZHVjYXRpb24gPC0gZGVtb190cmlnbHkgJT4lCiAgZmlsdGVyKERNREhSRURVIDw9IDUpCgpwIDwtIGdncGxvdChkYXRhID0gZGVtb190cmlnbHlfZWR1Y2F0aW9uLCBtYXBwaW5nID0gYWVzKHggPSBETURIUkVEVSwgeSA9IExCRExETCkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiNGRkMzMDAiLCBhbHBoYSA9IDAuNCkgKwogIGdlb21fc21vb3RoKHNpemUgPSAxLjEsIG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoCiAgICAgZmlsbD0iI0ZGN0QwNSIsIHNpemU9MS41LCBsaW5ldHlwZT0ic29saWQiCiAgICAgKSxwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEpCiAgICAgKSsKICBmYWNldF93cmFwKH5SSVNLLCBuY29sID0gMykgKwogIGxhYnMoeCA9ICJFZHVjYXRpb24gTGV2ZWwgKDEgLSBsb3dlc3QsIDUgLSBoaWdoZXN0KSIsCiAgICAgICB5ID0gIkxETCBMZXZlbHMiLAogICAgICAgdGl0bGUgPSAiSGVhcnQgZGlzZWFzZSByaXNrIGJ5IGVkdWNhdGlvbiBsZXZlbCIsCiAgICAgICBzdWJ0aXRsZSA9ICJSaXNrIGJhc2VkIG9uIExETCBsZXZlbCIpCmdncGxvdGx5KHApCmBgYAojIyMjIEFubnVhbCBob3VzZWhvbGQgaW5jb21lIG9mIHBhdGllbnRzIGluIHN0dWR5CmBgYHtyfQp0YWJsZShkZW1vX3RyaWdseSRJTkRISElOMikKYGBgCiMjIyMgVmlzdWFsaXppbmcgSGVhcnQgZGlzZWFzZSByaXNrIGJ5IEFubnVhbCBob3VzZWhvbGQgaW5jb21lCmBgYHtyfQpwIDwtIGdncGxvdChkYXRhID0gZGVtb190cmlnbHksIG1hcHBpbmcgPSBhZXMoeCA9IElOREhISU4yLCBmaWxsID0gUklTSykpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjcpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjM1MDAiLCAiI0ZGQzMwMCIsICIjRkY3RDA1IikpICsKICBsYWJzKHggPSAiQW5udWFsIEhvdXNlaG9sZCBJbmNvbWUgKDEgLSBsb3dlc3QsIDEwMCAtIGhpZ2hlc3QpIiwKICAgICAgIHkgPSAiUmlzayBzY29yZSIsCiAgICAgICB0aXRsZSA9ICJIZWFydCBkaXNlYXNlIHJpc2sgYnkgYW5udWFsIGhvdXNlaG9sZCBpbmNvbWUiLAogICAgICAgc3VidGl0bGUgPSAiUmlzayBiYXNlZCBvbiBMREwgbGV2ZWwiKQpnZ3Bsb3RseShwKQpgYGAKCiMjIyMgVmlzdWFsaXppbmcgTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljcyByZWdpb24KYGBge3J9CiMgZmlsdGVyaW5nIE1hcnlsYW5kIHJlZ2lvbiwgd2hlcmUgTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljcyBpcyBsb2NhdGVkIGF0CnN0YXRlcyA8LSBtYXBfZGF0YSgic3RhdGUiKQoKbmNoc19yZWdpb24gPC0gc3RhdGVzICU+JQogIGZpbHRlcihyZWdpb24gPT0gJ21hcnlsYW5kJykKCnAgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9seWdvbihkYXRhID0gc3RhdGVzLCBhZXMoeD1sb25nLHk9bGF0LCBncm91cCA9IGdyb3VwLCBmaWxsPXJlZ2lvbiksY29sb3I9IndoaXRlIiwgYWxwaGEgPSAwLjMpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IG5jaHNfcmVnaW9uLCBhZXMoeD1sb25nLHk9bGF0LCBncm91cCA9IGdyb3VwLCBmaWxsPXJlZ2lvbiksY29sb3I9IndoaXRlIikgKwogIGxhYnModGl0bGUgPSAiTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljcyAtIE1hcnlsYW5kIikgKwogIHRoZW1lX3ZvaWQoKQogIGd1aWRlcyhmaWxsID0gRkFMU0UpCmdncGxvdGx5KHApICU+JSBsYXlvdXQoc2hvd2xlZ2VuZCA9IEZBTFNFKQpgYGAKIyMjIyBWaXN1YWxpemluZyBOYXRpb25hbCBDZW50ZXIgZm9yIEhlYWx0aCBTdGF0aXN0aWNzIHJlZ2lvbgpgYGB7cn0KIyBOYXRpb25hbCBDZW50ZXIgZm9yIEhlYWx0aCBTdGF0aXN0aWNzIGNvb3JkZW5hdGVzIAptIDwtIGxlYWZsZXQoKSAlPiUKICBhZGRUaWxlcygpICU+JQogIGFkZE1hcmtlcnMobG5nPS03Ni45NTE3MjAsCiAgICAgICAgICAgICBsYXQ9MzguOTY5NDUwLAogICAgICAgICAgICAgbGFiZWw9Ik5hdGlvbmFsIENlbnRlciBmb3IgSGVhbHRoIFN0YXRpc3RpY3MiLAogICAgICAgICAgICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKG5vSGlkZT1UKSkKbQpgYGAKCgo=